//
// DebugManager.h
// ==============
// Provide a debug and log manager for system. Do not use DebugManager directly
// unless you must, inherit from DebugFrame instead.
//

#ifndef __DEBUG_MANAGER_H__
#define __DEBUG_MANAGER_H__

#include "SevenHeader.h"

#ifdef _DEBUG
#define dcnew new(std::nothrow, TEXT(__FILE__), __LINE__)
#define dcdelete delete
#else
#define dcnew cnew
#define dcdelete delete
#endif // _DEBUG

#define cnew new(std::nothrow)
#define cdelete delete

static const wchar_t *DEBUGMANAGER_DEFAULTLOGNAME = L"seven.log";
static const wchar_t *DEBUGMANAGER_WELCOMEMESSAGE = L" > Sevens' Stories: Log Started.\n\n";

class CDebugManager
{
public:
	// Factory Interfaces

	static void createInstance(void)
	{
		if(!_pDebugManager) {
			_pDebugManager = new CDebugManager();
		}
	}

	static void releaseInstance(void)
	{
		delete _pDebugManager;
		_pDebugManager = NULL;
	}

	static CDebugManager *getInstance(void)
	{
		return _pDebugManager;
	}

public:

	bool print(const wchar_t *pwszSourcePath,
			   UINT uLineNumber,
			   const wchar_t *pwszFunction,
			   const wchar_t *pwszMessage,
			   ...);

	void dumpCallStack(void);
	void printMemoryStatus(void);
	
	inline void printRawString(const wchar_t *str, ...)
	{
		const int max_buffer_length = 256;

		wchar_t msg[max_buffer_length];
		va_list arg;
		
		va_start(arg, str);
		_vsnwprintf(msg, max_buffer_length, str, arg);
		va_end(arg);
		_writeString(msg);
		_flushStream();
	}

	inline bool setOutputFileName(
		const wchar_t *pwszNewFileName = DEBUGMANAGER_DEFAULTLOGNAME)
	{
		if(_pLog) fclose(_pLog);
		_pLog = _wfopen(pwszNewFileName, L"w");
		if(!_pLog) return false;
		fputws(DEBUGMANAGER_WELCOMEMESSAGE, _pLog);
		return true;
	}

	static void _onAllocation(size_t uSize, 
							  const wchar_t *pwszSymbol,
							  const wchar_t *pwszFileName,
							  UINT uLineNumber,
							  void *pAddress);
	static void _onDeallocation(void *pAddress);

private:
	CDebugManager(void);
	~CDebugManager(void);

	void _freeAllocList(void);

	inline void _writeString(const wchar_t *str)
	{
		if(_pLog) {
			fwprintf(_pLog, L"%s", str);
		} else {
			if(setOutputFileName()) {
				fwprintf(_pLog, L"%s", str);
			}
		}
	}

	inline void _flushStream(void)
	{
		fflush(_pLog);
	}

private:
	FILE	*_pLog;

	struct AllocListElement
	{
		wchar_t	symbol[32];
		wchar_t	source[32];
		size_t	size;
		int		line;
	};

	static std::map<void *, AllocListElement *> _pAllocList;
	static CDebugManager *_pDebugManager;

private:
	// Forbid copying and assignment.
	CDebugManager(CDebugManager &mgr);
	CDebugManager &operator=(CDebugManager &rhs);
};


#endif // __DEBUG_MANAGER_H__
